package ca.camosun.morsecode;

import static ca.camosun.morsecode.nongui.MorseConstants.Token.DASH;
import static ca.camosun.morsecode.nongui.MorseConstants.Token.DOT;
import static ca.camosun.morsecode.nongui.MorseConstants.Token.LONG_PAUSE;
import static ca.camosun.morsecode.nongui.MorseConstants.Token.SHORT_PAUSE;
import ca.camosun.morsecode.nongui.MorseQueue;
import ca.camosun.morsecode.nongui.MorseVibrator;
import ca.camosun.morsecode.nongui.MorseConstants.Timing;
import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MorseButtonPadActivity extends Activity implements
		OnClickListener, CreateNdefMessageCallback {
	private MorseVibrator mVibrator;

	private Button dotButton;
	private Button dashButton;
	private Button shortPauseButton;
	private Button longPauseButton;
	private EditText readableMessage;
	private TextView receivedMessage;

	private MorseQueue toDecode = new MorseQueue();
	private Timing currentTiming;

	private NfcAdapter mNfcAdapter;

	private String toDeviceID;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.morse_buttons);

		mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
		if (mNfcAdapter != null) {
			mNfcAdapter.setNdefPushMessageCallback(this, this);
		}

		currentTiming = Timing.SLOW;

		mVibrator = new MorseVibrator(this.getApplicationContext(),
				currentTiming);
		dotButton = (Button) findViewById(R.id.dot);
		dashButton = (Button) findViewById(R.id.dash);
		shortPauseButton = (Button) findViewById(R.id.short_pause);
		longPauseButton = (Button) findViewById(R.id.long_pause);
		readableMessage = (EditText) findViewById(R.id.displayMorseMessage);
		receivedMessage = (TextView) findViewById(R.id.receivedMessage);

		dotButton.setOnClickListener(this);
		dashButton.setOnClickListener(this);
		shortPauseButton.setOnClickListener(this);
		longPauseButton.setOnClickListener(this);

		toDeviceID = "APA91bFsZGgga2h6I-gcqLssNRNOgPaBAY_Bx2MZ2hwq1mHMX9TyxB6lqh65gDLu4WGOkTK4E_A-R_zae0YF8lj5f0cF5CVszK3vfcP_TOmn9e_ss6vY5iDwvzsIJw5PGqFphkHyRKc2cA6AKh_zMlMpJTpB5bwl3w";

		try {
			GCMIntentService.register(this);
		} catch (Exception e) {
			Log.e(MorseButtonPadActivity.class.getName(), "No registration");
		}
	}

	@Override
	public void onClick(View applicationView) {

		switch (applicationView.getId()) {

		case R.id.dot:
			mVibrator.morseVibrate(DOT, currentTiming);
			toDecode.addToken(DOT);
			showToast(".");
			break;

		case R.id.dash:
			mVibrator.morseVibrate(DASH, currentTiming);
			toDecode.addToken(DASH);
			showToast("-");
			break;

		case R.id.short_pause:
			mVibrator.morseVibrate(SHORT_PAUSE, currentTiming);
			toDecode.addToken(SHORT_PAUSE);
			showToast("short pause");
			outputMessage();
			break;

		case R.id.long_pause:
			mVibrator.morseVibrate(LONG_PAUSE, currentTiming);
			toDecode.addToken(LONG_PAUSE);
			showToast("long pause");
			outputMessage();
			break;

		default:
			break;
		}
	}

	private void outputMessage() {
		String decoded = "";
		while (toDecode.hasNext()) {
			decoded += toDecode.getNextDecoded();
		}

		readableMessage.append(decoded);
		sendMessageToServer(decoded);
	}

	private void outputReceivedMessage(String message) {
		receivedMessage.setText(message);
	}

	private void showToast(String text) {
		Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
		toast.setGravity(Gravity.BOTTOM | Gravity.CENTER, 0, 0);
		toast.show();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater menuInflater = getMenuInflater();
		menuInflater.inflate(R.menu.option_menu, menu);
		return true;
	}

	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);

		setIntent(intent);

		if (intent.getBooleanExtra("gcmIntentServiceMessage", false) == false) {
			return;
		}

		if (intent.getBooleanExtra("registrationMessage", true)) {
			System.out.println("register");
			return;
		}

		/*
		 * if (intent.getBooleanExtra("error", true)) { return; }
		 */

		String message = intent.getStringExtra("message");
		if (message == null) {
			return;
		}
		outputReceivedMessage(message);
		mVibrator.vibrate(message);
	}

	public String toString() {
		return readableMessage.getText().toString();
	}

	public void sendMessageToServer(String message) {
		new SendResultToServerTask().execute(message);
	}

	private class SendResultToServerTask extends AsyncTask<String, Void, Void> {
		@Override
		protected Void doInBackground(String... message) {
			GCMIntentService.sendMessageToID(message[0], toDeviceID);
			return null;
		}

		@Override
		protected void onPostExecute(Void unused) {
		}
	}

	@Override
	public NdefMessage createNdefMessage(NfcEvent arg0) {
		String text = GCMIntentService
				.getDeviceRegistration(getApplicationContext());
		NdefMessage msg = new NdefMessage(NdefRecord.createMime(
				"application/ca.camosun.morsecode", text.getBytes())
		/**
		 * The Android Application Record (AAR) is commented out. When a device
		 * receives a push with an AAR in it, the application specified in the
		 * AAR is guaranteed to run. The AAR overrides the tag dispatch system.
		 * You can add it back in to guarantee that this activity starts when
		 * receiving a beamed message. For now, this code uses the tag dispatch
		 * system.
		 */
		// ,NdefRecord.createApplicationRecord("com.example.android.beam")
		);
		return msg;
	}

	@Override
	public void onResume() {
		super.onResume();
		// Check to see that the Activity started due to an Android Beam
		if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
			processIntent(getIntent());
		}
	}

	void processIntent(Intent intent) {
		Parcelable[] rawMsgs = intent
				.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
		// only one message sent during the beam
		NdefMessage msg = (NdefMessage) rawMsgs[0];
		// record 0 contains the MIME type, record 1 is the AAR, if present
		toDeviceID = new String(msg.getRecords()[0].getPayload());
	}
}
